//////////////////////////////////////////////////////////////////////
////                                                              		////
////  PHY_BEHAVIOR.v                                                   	////
////                                                              		////
////  This file is part of the Behavior Model of GPHY         ////
/*
    File Name:		Phy_sim.v
	Title:			Phy_sim
	Author:			chen
	Email:			dychen81@gmail.com
	Revision:		0.1
	Date:			2009-11-25
	Description:	a) Read packet data from rxdbuf.
					b) Generate GMII rx timing to phy_controller.

	----------------------------------------
    History
    ----------
    Date        By          Description
    ----------  ----------  --------------------------------------------------
    2009-11-26  Len D.      a) renamed to PHY_BEHAVIOR.
*/	


`timescale 1ns/100ps 

module PHY_BEHAVIOR (
input 			rst						,//system rest
input			Gtx_clk					,//used only in GMII mode
output			Rx_clk					,
output			Tx_clk					,//used only in MII mode
input			Tx_er					,
input			Tx_en					,
input	[7:0]	Txd						,
output			Rx_er					,
output	reg		Rx_dv					,
output 	reg [7:0]	Rxd						,
output			Crs						,
output			Col						,
input	[2:0]	Speed				
);

//////////////////////////////////////////////////////////////////////
// this file used to simulate Phy.
// generate clk and rx data flow to phy_controller
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// internal signals
//////////////////////////////////////////////////////////////////////
reg				Clk_125m			;//used for 1000Mbps mode
reg				Clk_25m			;//used for 100 Mbps mode
reg				Clk_2_5m		;//used for 10 Mbps mode
//wire			Rx_clk			;
//wire			Tx_clk			;//used only in MII mode
//////////////////////////////////////////////////////////////////////


	parameter	PKTFILE	= `PHY_PKTFILE;
	parameter	DATA_WIDTH	= 8;
	parameter	ADDR_WIDTH	= 10;
	parameter	ADDR_DEPTH	= 1 << ADDR_WIDTH;
	parameter      RX_IFG_SET      = 10;
	
	// port definitions.
	reg [ADDR_WIDTH : 0] Addr;
	reg [DATA_WIDTH-1 : 0] Data;

	// Ram declaration.
	reg [DATA_WIDTH-1 : 0] rxbuf [0 : ADDR_DEPTH - 1];

	// Initialization.
	integer i;
	initial
	begin
		Data = 0;
		for (i=0; i<ADDR_DEPTH; i=i+1)
			rxbuf[i] = 0;
		$readmemh(PKTFILE, rxbuf);
	end

	// Read mem.
	always @ (Addr)
	begin
		if (Addr >= ADDR_DEPTH)
		begin
			Data = 0;
			$display("Memory address overflow at 0x%h", Addr);
		end
		else
		begin
			Data = rxbuf[Addr];
		end
	end

//Generate grxc
always 
	begin
	#4		Clk_125m=0;
	#4		Clk_125m=1;
	end
//Generate 25MHz clk
always 
	begin
	#20		Clk_25m=0;
	#20		Clk_25m=1;
	end
//Generate 2.5MHz clk	
always  
	begin
	#200	Clk_2_5m=0;
	#200	Clk_2_5m=1;
	end   



assign 	Rx_clk=Speed[2]?Clk_125m:Speed[1]?Clk_25m:Speed[0]?Clk_2_5m:0;    
assign 	Tx_clk=Speed[2]?Clk_125m:Speed[1]?Clk_25m:Speed[0]?Clk_2_5m:0;


assign	Rx_er	=0		;
assign	Crs    	=Tx_en | Rx_dv	;
assign  	Col	=0		;



reg Ifg_done;
reg Rx_done;
reg [4:0] Ifg_cnt;


always @(posedge Rx_clk or negedge rst)
if  (!rst)
begin
	Ifg_done <= 0;
	Ifg_cnt <= 0;
end
else if (Rx_done)
        begin
        	Ifg_done <= 0;
        	Ifg_cnt <= 0;        
        end
        else if (Ifg_done == 0 && Ifg_cnt == RX_IFG_SET)
	       begin
               Ifg_done <= 1;
               Ifg_cnt <= 0;
               end
	else
	       begin
	       Ifg_cnt <= Ifg_cnt + 1;
	       end


always @(posedge Rx_clk or negedge rst)
if (!rst)
begin
        Rx_done <= 0;
        Rx_dv   <= 0;
        Rxd     <= 0;
        Addr    <= 0;
end
else if (Ifg_done)
        begin
                if (Rx_done == 0 && Addr == ADDR_DEPTH -1 )
                begin
                        Addr    <= Addr + 1;                
                        Rx_done <= 1;
                        Rx_dv   <= 1;     
                        Rxd     <= Data;
			$monitor ($time,"rxc = %b, rxdv = %b,rxd = %8h",Rx_clk,Rx_dv,Rxd);
                        
                end
                else if (Rx_done == 1 && Addr == ADDR_DEPTH )
                begin
                        Rx_dv   <= 0;
                        Rxd     <= Data;
                        Rx_done <= 0;
                        Addr    <= 0;             
			$monitor ($time,"rxc = %b, rxdv = %b,rxd = %8h",Rx_clk,Rx_dv,Rxd);
                end
                else 
                begin
                        Addr    <= Addr + 1;
                        Rx_dv   <= 1;                        
                        Rxd     <= Data;
                        Rx_done <= 0;
			$monitor ($time,"rxc = %b, rxdv = %b,rxd = %8h",Rx_clk,Rx_dv,Rxd);
                        
                end
          end
        else
        begin
                        Rx_dv   <= 0;
                        Rxd     <= 0;
                        Rx_done <= 0;
                        Addr    <= 0;
			$monitor ($time,"rxc = %b, rxdv = %b,rxd = %8b",Rx_clk,Rx_dv,Rxd);
                        
        end

endmodule
